/*
	The Shadow Framework - a complete framework for Real Time Graphics based on OpenGL
    Copyright (C) 2008  Alessandro Martinelli  <alessandro.martinelli@unipv.it>

    This file is part of The Shadow Framework.

    The Shadow Framework is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    The Shadow Framework is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Shadow Framework.  If not, see <http://www.gnu.org/licenses/>.
*/

package objLoader.math;

public class MatrixNf {

	private float matrix[];
	private int dimension;
	
	
	public MatrixNf(int dimension) {
		super();
		this.dimension = dimension;
		matrix=new float[dimension*dimension];
	}
	
	public MatrixNf multiply(MatrixNf b){
		MatrixNf c=new MatrixNf(dimension);
		
		if(b.dimension==dimension){
			
			for(int i=0;i<dimension;i++){
				
				for(int j=0;j<dimension;j++){
					
					int index=j+i*dimension;//Posizione in c
					
					float sum=0;
					for(int k=0;k<dimension;k++){//La riga i della prima matrice + la colonna j della seconda 
						sum+=matrix[k+i*dimension]*b.matrix[j+k*dimension];
						//System.out.println("	A "+matrix[k+i*dimension]);
						//System.out.println("	b "+b.matrix[j+k*dimension]);
					}
					
					//System.out.println("sum "+sum);
					c.matrix[index]=sum;
				}
			}
		}
		
		return c;
	}
	
	
	public MatrixNf getIdentity(){
		MatrixNf ret=new MatrixNf(dimension);
		for(int i=0;i<dimension;i++){
			ret.matrix[i*(1+dimension)]=1;
		}
		return ret;
	}
	
	public void setIdentity(){
		for(int i=0;i<dimension;i++){
			matrix[i*(1+dimension)]=1;
		}
	}
	
	public MatrixNf matrixLess(int r,int c){
		int dim=dimension-1;
		MatrixNf m=new MatrixNf(dim);
		for(int j=0;j<dim;j++){
			for(int k=0;k<dim;k++){
				int row=j;
				int col=k;
				if(row>=r)
					row++;
				if(col>=c)
					col++;	
				if(c>=dimension)
					c-=dimension;
				m.matrix[j*dim+k]=matrix[row*dimension+col];
			}
		}
		System.out.println(m);
		return m;
	}
	
	public float determinant(){
		if(dimension==2)
			return matrix[0]*matrix[3]-matrix[1]*matrix[2];
		int dim=dimension-1;
		float sum=0;
		for(int i=0;i<dimension;i++){	
			MatrixNf m=new MatrixNf(dim);
			for(int j=0;j<dim;j++){
				for(int k=0;k<dim;k++){
					int r=j+1;
					int c=i+k;
					if(c>=dimension)
						c-=dimension;
					m.matrix[j*dim+k]=matrix[r*dimension+c];
				}
			}
			float f=m.determinant();
			if(i%2==0)
				sum+=f*matrix[i];
			else
				sum-=f*matrix[i];
		}
		return sum;
	}
	
	public MatrixNf getInversa(){
		MatrixNf mm=new MatrixNf(dimension);
		float f=determinant();
		if(f!=0)
			for(int i=0;i<dimension;i++){
				for(int j=0;j<dimension;j++){
					MatrixNf m=matrixLess(i, j);
					float det=m.determinant();
					mm.matrix[j+i*dimension]=det/f;
				}
			}
		return mm;
	}
	
	public String toString(){
		
		String s="";
		
		for(int i=0;i<dimension;i++){
			for(int j=0;j<dimension;j++){
				s+=matrix[j+i*dimension]+" ";
			}
			s+="\n";
		}
		
		return s;
	}

	public static void main(String[] args) {
		
		MatrixNf m=new MatrixNf(3);
		MatrixNf m1=new MatrixNf(3);
		
		m.setIdentity();
		
		m.matrix[0]=1;
		m.matrix[1]=1;
		m.matrix[2]=1;
		
		System.out.println(m);
		System.out.println("");
		System.out.println(m.determinant());
		
		System.out.println("");
		
		m1=m.getInversa();
		
		System.out.println(m1);
		
		MatrixNf m2=m.multiply(m1);
		
//		System.out.println(m);
//		System.out.println(m1);
//		System.out.println(m2);
//		
		System.out.println(m2);
	}
}
